package tpase.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
import tpase.GlobalServer.VO.MessageCode;

import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Properties;

public class Util {

    /**
     * 向 .properties文件file插入 key = value
     * @param filePath 文件的路径，如 config/parameters.properties
     * @param key 名称
     * @param value 值
     */
    public static void setProperty(String filePath, String key, String value) {
        Properties properties = new Properties();
        try {
            InputStream inputStream = ClassLoader.getSystemResourceAsStream(filePath);
            properties.load(inputStream);
            properties.setProperty(key, value);
            OutputStream outputStream = filePathToFileOutputStream(filePath);
            properties.store(outputStream, "modify");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取 .properties文件中 key 对应的值
     * @param file 文件的路径，如 config/parameters.properties
     * @param key 名称
     * @return 返回对应的值
     */
    public static String getProperty(String file, String key) {
        Properties properties = new Properties();
        String value;
        try {
            InputStream inputStream = ClassLoader.getSystemResourceAsStream(file);
            properties.load(inputStream);
            value = properties.getProperty(key);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return value;
    }

    /**
     * 清空 .properties 文件
     * @param filePath 文件的路径，如 config/parameters.properties
     */
    public static void clearProperty(String filePath) {
        Properties properties = new Properties();
        try {
            InputStream inputStream = ClassLoader.getSystemResourceAsStream(filePath);
            properties.load(inputStream);
            properties.clear();
            OutputStream outputStream = filePathToFileOutputStream(filePath);
            properties.store(outputStream, "modify");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据文件路径转换为 FileOutputStream 对象
     * @param filePath 文件的路径，如 config/parameters.properties
     * @return FileOutputStream
     */
    public static FileOutputStream filePathToFileOutputStream(String filePath) {
        URL url = ClassLoader.getSystemResource(filePath);
        try {
            String decodePath = URLDecoder.decode(url.getFile(), "UTF-8");
            return new FileOutputStream(new File(decodePath));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Pairing getPairing(String path) {
        return PairingFactory.getPairing(path);
    }

    public static void processServerBootstrap(ChannelInboundHandlerAdapter channelInboundHandlerAdapter, int port) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);

            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline channelPipeline = socketChannel.pipeline();
//                    channelPipeline.addLast(new LoggingHandler(LogLevel.INFO));
                    channelPipeline.addLast(new LengthFieldBasedFrameDecoder(1024 * 1024 * 10, 0, 4, 0, 0));

                    channelPipeline.addLast(new MessageCode());
                    channelPipeline.addLast(channelInboundHandlerAdapter);
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static <T> T jsonToObject(String json, Class<T> cls) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(json, cls);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static String toJson(Object obj) {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T jsonFileToObj(String path, Class<T> cls) {
        ObjectMapper mapper = new ObjectMapper();
        T t = null;
        try {
            File f = new File(path);
            FileReader fileReader = new FileReader(f);
            Reader reader = new InputStreamReader(new FileInputStream(f), "Utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            fileReader.close();
            reader.close();
            String jsonStr = sb.toString();
            t= mapper.readValue(jsonStr, cls);
            //t = mapper.readValue(new File(path), cls);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return t;
    }

    public static byte[] intToByteArr(int value) {
        byte[] idxBytes = new byte[1];
        idxBytes[0] = (byte) value;
        return idxBytes;
    }

    public static void main(String[] args) {
        String filePath = "config/parameters.properties";
        System.out.println(Util.getProperty(filePath, "t"));

    }
}
